package dpda;

import org.junit.jupiter.api.Test;
import pda.PDAConfiguration;
import pda.PDARule;
import pda.Stack;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author haoly
 * @title DPDATest
 * @date 2025/4/21 11:12
 * @description TODO
 */
public class DPDATest {
    @Test
    public void testAccepting() {
        List<PDARule<Integer>> rules = Arrays.asList(
                new PDARule<>(1, '(', 2, '$', "b$"),
                new PDARule<>(2, '(', 2, 'b', "bb"),
                new PDARule<>(2, ')', 2, 'b', ""),
                new PDARule<>(2, null, 1, '$', "$")
        );
        DPDARulebook<Integer> rulebook = new DPDARulebook<>(rules);

        Stack<Character> stack = new Stack<>(Arrays.asList('$'));
        PDAConfiguration<Integer> configuration = new PDAConfiguration<>(1, stack);

        DPDA<Integer> dpda = new DPDA<>(configuration, Set.of(1), rulebook);
        System.out.println(dpda);

        assertTrue(dpda.accetpting());
    }

    @Test
    public void testReadString() {
        List<PDARule<Integer>> rules = Arrays.asList(
                new PDARule<>(1, '(', 2, '$', "b$"),
                new PDARule<>(2, '(', 2, 'b', "bb"),
                new PDARule<>(2, ')', 2, 'b', ""),
                new PDARule<>(2, null, 1, '$', "$")
        );
        DPDARulebook<Integer> rulebook = new DPDARulebook<>(rules);

        Stack<Character> stack = new Stack<>(Arrays.asList('$'));
        PDAConfiguration<Integer> configuration = new PDAConfiguration<>(1, stack);

        DPDA<Integer> dpda = new DPDA<>(configuration, Set.of(1), rulebook);
        System.out.println(dpda);

        assertTrue(dpda.accetpting());
        dpda.readString("(()");
        assertEquals(2, dpda.getCurrentConfiguration().getState());
        assertFalse(dpda.accetpting());

        System.out.println(dpda.getCurrentConfiguration());
    }

    @Test
    public void testMixed() {
        List<PDARule<Integer>> rules = Arrays.asList(
                new PDARule<>(1, '(', 2, '$', "b$"),
                new PDARule<>(2, '(', 2, 'b', "bb"),
                new PDARule<>(2, ')', 2, 'b', ""),
                new PDARule<>(2, null, 1, '$', "$")
        );
        DPDARulebook<Integer> rulebook = new DPDARulebook<>(rules);

        Stack<Character> stack = new Stack<>(Arrays.asList('$'));
        PDAConfiguration<Integer> configuration = new PDAConfiguration<>(1, stack);

        DPDA<Integer> dpda = new DPDA<>(configuration, Set.of(1), rulebook);
        System.out.println(dpda);

        assertTrue(dpda.accetpting());
        dpda.readString("(()(");
        assertEquals(2, dpda.getCurrentConfiguration().getState());
        assertFalse(dpda.accetpting());
        System.out.println(dpda.getCurrentConfiguration());

        dpda.readString("))()");
        assertEquals(1, dpda.getCurrentConfiguration().getState());
        assertTrue(dpda.accetpting());
        System.out.println(dpda.getCurrentConfiguration());

    }

    @Test
    public void testMixed2() {
        List<PDARule<Integer>> rules = Arrays.asList(
                new PDARule<>(1, '(', 2, '$', "b$"),
                new PDARule<>(2, '(', 2, 'b', "bb"),
                new PDARule<>(2, ')', 2, 'b', ""),
                new PDARule<>(2, null, 1, '$', "$")
        );
        DPDARulebook<Integer> rulebook = new DPDARulebook<>(rules);

        Stack<Character> stack = new Stack<>(Arrays.asList('$'));
        PDAConfiguration<Integer> configuration = new PDAConfiguration<>(1, stack);

        DPDA<Integer> dpda = new DPDA<>(configuration, Set.of(1), rulebook);
        System.out.println(dpda);

        dpda.readString("())");
        System.out.println(dpda.getCurrentConfiguration());
        assertFalse(dpda.accetpting());
        assertFalse(dpda.isStuck());
    }
}
